﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq.Expressions;


namespace GeneralServices.ViewModel
{
    /// <summary>
    /// Base class for all ViewModel classes in the application. Provides support for 
    /// property changes notification.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region PropertyChanged

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Warns the developer if this object does not have a public property with
        /// the specified name. This method does not exist in a Release build.
        /// </summary>
        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            // verify that the property name matches a real,  
            // public, instance property on this object.
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                Debug.Fail("Invalid property name: " + propertyName);
            }
        }

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The name of the property that has a new value.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        /// <summary>
        /// Permet de notifier les observeurs d'une propriété grâce à une lambda expression.
        /// </summary>
        protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            if (this.PropertyChanged != null)
            {
                OnPropertyChanged((propertyExpression.Body as MemberExpression).Member.Name);
            }
        }
        #endregion

        #region ActionVMLaunched

        /// <summary>
        /// Levé quand une action du type ouverture fenêtre à été lancé (typiquement : Ouverture d'une nouvelle fenêtre grâce à un UserControl
        /// </summary>
        /// <param name="sender">Objet émetteur</param>
        /// <param name="action">Arguments de l'action</param>
        public delegate void ActionVMLaunched(object sender, ActionVMArgs action);
        public event ActionVMLaunched ActionVM;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="action">Action done</param>
        protected virtual void OnActionVM(ActionVMArgs action)
        {
            if (ActionVM != null)
                ActionVM(this, action);
        }

        #endregion

        #region ActionVMClosed

        /// <summary>
        /// Levé quand une action du type fermeture de la fenêtre lancé (typiquement : Fermeture d'une nouvelle fenêtre)
        /// </summary>
        /// <param name="sender">Objet émetteur</param>
        /// <param name="action">Arguments de l'action</param>
        public delegate void ActionVMClosed(object sender, ActionVMArgs action);
        public event ActionVMClosed ActionVMClose;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="action">Action done</param>
        protected virtual void OnActionVMClosed(ActionVMArgs action)
        {
            if (ActionVMClose != null)
                ActionVMClose(this, action);
        }

        #endregion
    }
}
